/**
 * 开发团队 : 未来科技
 * 开发人员 : ww
 * 开发时间 : 2020/5/16 11:46 AM
 * 文件名称 : acessToken.js
 * 开发工具 : WebStorm
 * 功能描述 : https请求方式: GET
 * https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
 */

const rp = require('request-promise-native')
const { writeFile, readFile } = require('fs')

const {appID, appsecret} = require('../config')
const api = require('../utils/api')
const menu = require('./menu')
const { writeFileAsync, readFileAsync } = require('../utils/tool')


class Wechat {

    constructor() {

    }

    /**
     * 获取access_token
     */
    getAccessToken() {
        // 定义请求地址
        const url = `${api.accessToken}&appid=${appID}&secret=${appsecret}`
        // 发送请求 request request-promise-native
        return new Promise((resolve, reject) => {
            rp({method: 'GET', url, json: true})
                .then(res => {
                    // 设置access_token 过期时间
                    res.expires = Date.now() + (res.expires_in - 300) * 1000
                    // 将promise对象状态改成成功的状态
                    resolve(res)
                })
                .catch(err => {
                    // 将promise对象状态改成失败的状态
                    reject('getAccessToken' + err)
                })
        })

    }

    /**
     * 保存access_token到本地
     * @param accessToken 要保存的凭据
     */
    saveAccessToken(accessToken) {

        return writeFileAsync(accessToken, 'access_token.txt')
    }

    /**
     * 读取本地access_token
     */
    readAccessToken() {

        return readFileAsync('access_token.txt')
    }

    /**
     * 判断access_token 是否有效
     * @param data
     */
    isValidAccessToken(data) {
        // 判断传入数据是否有效
        if (!data && !data.sccess_token && !data.expires_in) {
            return false
        }

        // 判断access_token 是否在有效期内
        return data.expires_in > Date.now()
    }

    /**
     *  获取没有过期的 access_token
     * @returns {Promise}
     */
    fetchAccessToken() {

        if (this.access_token && this.expires_in && this.isValidAccessToken(this)) {
            return Promise.resolve({
                access_token: this.access_token,
                expires_in: this.expires_in
            })
        }

        return this.readAccessToken()
            .then(async res => {
                // 本地文件
                // 判断 access_token 是否过期
                if (this.isValidAccessToken(res)) {
                    // access_token 在有效期内
                    return Promise.resolve(res)
                } else {
                    // access_token 过期
                    // 发送请求获取 access_token
                    const res = await this.getAccessToken()
                    //保存本地文件
                    await this.saveAccessToken(res)
                    // 将请求回来的 access_token 返回
                    return Promise.resolve(res)
                }
            })
            .catch(async err => {
                // 本地没有文件
                // 发送请求获取 access_token
                const res = await this.getAccessToken()
                //保存本地文件
                await this.saveAccessToken(res)
                // 将请求回来的 access_token 返回
                return Promise.resolve(res)
            })
            .then(res => {
                // 将access_token 挂在到this上
                this.access_token = res.access_token
                this.expires_in = res.expires_in

                return Promise.resolve(res)
            })
    }

    /**
     * 获取jsapi_ticket
     */
    getTicket() {

        // 发送请求 request request-promise-native
        return new Promise(async (resolve, reject) => {
            // 获取 ticket
            const data = await this.fetchAccessToken()
            // 定义请求地址
            const url = `${api.ticket}&access_token=${data.access_token}`

            rp({method: 'GET', url, json: true})
                .then(res => {
                    // 将promise对象状态改成成功的状态
                    resolve({
                        ticket: res.ticket,
                        expires_in: Date.now() + (res.expires_in - 300) * 1000
                    })
                })
                .catch(err => {
                    // 将promise对象状态改成失败的状态
                    reject('getTicket' + err)
                })
        })

    }

    /**
     * 保存jsapi_ticket到本地
     * @param ticket 要保存的凭据
     */
    saveTicket(ticket) {

        return writeFileAsync(ticket, 'ticket.txt')
    }

    /**
     * 读取本地jsapi_ticket
     */
    readTicket() {

        return readFileAsync('ticket.txt')
    }

    /**
     * 判断jsapi_ticket 是否有效
     * @param data
     */
    isValidTicket(data) {
        // 判断传入数据是否有效
        if (!data && !data.ticket && !data.expires_in) {
            return false
        }

        // 判断ticket 是否在有效期内
        return data.expires_in > Date.now()
    }

    /**
     * 获取没有过期的 ticket
     * @returns {Promise}
     */
    fetchTicket() {

        if (this.ticket && this.ticket_expires_in && this.isValidTicket(this)) {
            // ticket 没有过期, 直接使用
            return Promise.resolve({
                ticket: this.ticket,
                expires_in: this.ticket_expires_in
            })
        }

        return this.readTicket()
            .then(async res => {
                // 本地文件
                // 判断 ticket 是否过期
                if (this.isValidTicket(res)) {
                    // ticket 在有效期内
                    return Promise.resolve(res)
                } else {
                    // ticket 过期
                    // 发送请求获取 ticket
                    const res = await this.getTicket()
                    //保存本地文件
                    await this.saveTicket(res)
                    // 将请求回来的 ticket 返回
                    return Promise.resolve(res)
                }
            })
            .catch(async err => {
                // 本地没有文件
                // 发送请求获取 ticket
                const res = await this.getTicket()
                //保存本地文件
                await this.saveTicket(res)
                // 将请求回来的 ticket 返回
                return Promise.resolve(res)
            })
            .then(res => {
                // 将 ticket 挂在到this上
                this.ticket = res.access_token
                this.ticket_expires_in = res.expires_in

                return Promise.resolve(res)
            })
    }


    /**
     * 创建自定菜单
     * @param menu
     * @returns {Promise}
     */
    createMenu(menu) {
        return new Promise(async (resolve, reject) => {
            try {
                // 获取access_token
                const data = await this.fetchAccessToken()
                // 定义请求地址
                const url = `${api.menu.create}access_token=${data.access_token}`
                // 发送请求
                const result = await rp({method: 'POST', url, json: true, body: menu})
                resolve(result)
            } catch (e) {
                reject('createMenu: ' + e)
            }

        })
    }

    /**
     * 删除自定菜单
     * @returns {Promise}
     */
    deleteMenu() {
        return new Promise(async (resolve, reject) => {
            try {
                // 获取access_token
                const data = await this.fetchAccessToken()
                // 定义请求地址
                const url = `${api.menu.delete}access_token=${data.access_token}`
                // 发送请求
                const result = await rp({method: 'GET', url, json: true})
                resolve(result)
            } catch (e) {
                reject("deleteMenu: " + e)
            }
        })
    }
}

(async () => {
    const wx = new Wechat()
    // let result = await wx.deleteMenu()
    // console.log(result)
    //
    // result = await wx.createMenu(menu)
    // console.log(result)

    // const data = await wx.fetchTicket()
    // console.log(data)
})()


module.exports = Wechat